Completed
Pull Request — master (#71)
by Marcelo
30s
created

input.js ➔ toInquirerQuestion   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
c 2
b 0
f 0
nc 3
nop 1
dl 0
loc 9
rs 9.6666
1
import { resolve } from 'bluebird';
2
import {
3
    T,
4
    __,
5
    assoc,
6
    concat,
7
    cond,
8
    curry,
9
    has,
10
    keys,
11
    map,
12
    merge,
13
    reduce,
14
    toPairs
15
} from 'ramda';
16
import { green, red, yellow } from 'colors/safe';
17
import { createPromptModule } from 'inquirer';
18
import DatePickerPrompt from 'inquirer-datepicker-prompt';
19
import ChalkPipe from 'inquirer-chalk-pipe';
20
import AutocompletePrompt from 'inquirer-autocomplete-prompt';
21
import { validator, filter } from './types';
22
import getAutocompleteSources, { compileClosure } from './autocomplete';
23
24
/**
25
 * Emits a warning to stdout
26
 *
27
 * @param {String} message
28
 * @return {Promise}
29
 */
30
export const emitWarning = concat(' ⚠ Warning: ') & yellow & console.log & resolve;
31
32
/**
33
 * Emits an error to stdout
34
 *
35
 * @param {String} message
36
 * @return {Promise}
37
 */
38
export const emitError = concat(' ✗ Error: ') & red & console.log & resolve;
39
40
/**
41
 * Emits a success message
42
 *
43
 * @param {String} message
44
 * @return {Promise}
45
 */
46
export const emitSuccess = concat(' ✔ Success: ') & green & console.log & resolve;
47
48
/**
49
 * Renames the keys of an object
50
 *
51
 * @sig {a: b} -> {a: *} -> {b: *}
52
 */
53
const renameKeys = curry((keysMap, obj) => reduce((acc, key) =>
54
    assoc(keysMap[key] || key, obj[key], acc), {}, keys(obj)));
55
56
const components = {
57
    Calendar: ~{
58
        type: 'datetime',
59
        format: ['m', '/', 'd', '/', 'yy'],
60
        filter: filter.Calendar },
61
    Char: ({ length }) => ({ filter: filter.Char(length) }),
62
    Checkbox: ~{ type: 'confirm' },
63
    Color: ~{ type: 'chalk-pipe' },
64
    DoubleRange: ({ from, to }) => ({
65
        filter: filter.Double,
66
        validate: validator.Range(from, to) }),
67
    DateTime: ~{ type: 'datetime' },
68
    Double: ~{ validate: validator.Double, filter: filter.Double },
69
    Email: ~{ validate: validator.Email },
70
    Integer: ~{ validate: validator.Integer, filter: filter.Integer },
71
    IntegerRange: ({ from, to }) => ({
72
        filter: filter.Integer,
73
        validate: validator.Range(from, to) }),
74
    IntegerMultiRange: ({ from, to }) => ({
75
        filter: filter.IntegerMultiRange,
76
        validate: validator.IntegerMultiRange(from, to) }),
77
    Natural: ~{ validate: validator.Natural, filter: filter.Integer },
78
    OneOf: ({ values }) => ({ type: 'list', choices: values }),
79
    String: ~{ type: 'input' },
80
    Url: ~{ validate: validator.Url },
81
    Money: ~{ validate: validator.Money, filter: filter.Money },
82
    SelectBox: ({ values }) => ({
83
        type: 'list',
84
        choices: values
85
            | toPairs
86
            | map(([value, name]) => ({ name, value })) })
87
};
88
89
/**
90
 * Custom autocomplete component
91
 *
92
 * @param {String} name
93
 * @param {String} source
94
 * @return {Function}
95
 */
96
const getAutocompleteComponent = (name, source) => {
97
    if (!source) {
98
        throw new Error(`aren't you missing 'autocomplete/${name}.js'?`);
99
    }
100
101
    return ~{ type: 'autocomplete', source: compileClosure(name, source) };
102
};
103
104
/**
105
 * Converts a Rung CLI question object to an Inquirer question object
106
 *
107
 * @author Marcelo Haskell Camargo
108
 * @param {String[]} sources
109
 * @param {String} name
0 ignored issues
show
Documentation introduced by
The parameter name does not exist. Did you maybe forget to remove this comment?
Loading history...
110
 * @param {Object} config
0 ignored issues
show
Documentation introduced by
The parameter config does not exist. Did you maybe forget to remove this comment?
Loading history...
111
 * @return {Object}
112
 */
113
const toInquirerQuestion = curry((sources, [name, config]) => {
114
    const component = components
115
        | cond([
116
            [~(config.type.name === 'AutoComplete'), ~getAutocompleteComponent(name, sources[name])],
117
            [has(config.type.name), _[config.type.name]],
0 ignored issues
show
Bug introduced by
The variable _ seems to be never declared. If this is a global, consider adding a /** global: _ */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
118
            [T, _.String]
119
        ]);
120
121
    return merge(config
122
        | renameKeys({ description: 'message' })
123
        | merge(__, { name }), component(config.type));
124
});
125
126
/**
127
 * Returns the pure JS values from received questions that will be answered
128
 *
129
 * @author Marcelo Haskell Camargo
130
 * @param {Object} questions
131
 * @return {Promise} answers for the questions by key
132
 */
133
export function ask(questions) {
134
    const prompt = createPromptModule();
135
    prompt.registerPrompt('datetime', DatePickerPrompt);
136
    prompt.registerPrompt('chalk-pipe', ChalkPipe);
137
    prompt.registerPrompt('autocomplete', AutocompletePrompt);
138
    return getAutocompleteSources()
139
        .then(autocompleteSources => questions
140
            | toPairs
141
            | map(toInquirerQuestion(autocompleteSources))
142
            | prompt);
143
}
144